Lab 4 - Fork Watcher
If you are unable to complete the lab as such, you are still responsible for understanding the relevant material.
In this lab, you will gather information about each fork call executed.  When a fork is performed, you will collect some "interesting" information, and store it in a circular ring buffer. Once you have instrumented the kernel to collect the information and save it in your ring buffer, you will then write an installable module to fetch and display that information to a user via the /proc filesystem.
Getting Started:
Take a look at Linux Data Structures, and find the section on task_struct. Look at what is contained in a task_struct. In particular, look for how you get the PID, UID and command of the current task from this structure. Remember that this is the process control block for all processes in a Linux system. You may also want to review your notes or the text book on how the fork system call works.
http://www.tldp.org/LDP/tlk/ds/ds.html
Next, go into the kernel source, and find the file fork.c. Spend some time looking at the function kernel_clone, and figure out exactly when it creates the child process. You might also want to spend some time looking at copy_process to help your understanding. Look at how you could retrieve the clone_flags used for creating the new process. The clone man page has a lot of information about the clone flags and what they mean.
https://github.com/torvalds/linux/blob/master/kernel/fork.c
https://linux.die.net/man/2/clone
https://www.tecmint.com/linux-process-management/
In the kernel, the macro named current, evaluates to a pointer to the task_struct of the current thread. Again, as you look at kernel_clone, think about how you would use current to get information about the parent process of the fork.
Part I: Modifying the kernel:
Information to collect:
•	The clone flags
•	The parent PID
•	The child PID
•	The parent UID (you can do this by using the cred pointer in the current process: current->cred->euid.val;
•	The name of the command from which the process was created (use get_task_comm(<place to put the command>, current);)
•	The return value from the fork of the child process 
This information is either in the task_struct, or else available to you within kernel_clone. In a new header file named fork_info.h, create a struct fork_info that will hold this information. Use the information you've gathered above to help you figure out the type of each element within your structure. You will probably need to include <linux/sched.h> and <linux/types.h>. Don't forget your include guards!
Once you've created your header file, include it in the directory with the other Linux include files (like sched.h and types.h).
Ring Buffer:
Once you have your structure defined, you need to create a ring buffer to hold copies of your structure. The easiest way to implement a ring buffer is as an array of your new structure. You'll then need two index variables (or pointers, but I suspect index variables are easier). One should indicate the next available slot in the buffer (where you'd want to write the next record), and one to indicate the next item to remove from the buffer.
To work with this ring buffer, you'll want to write two functions:  
void put_fork_record(const struct fork_info *p)  where do_fork will insert new records into your buffer, and int get_fork_record (struct fork_info *p), which your /proc module will use to read records out of your buffer. 
Some pseudo code for put_fork_record:
•	Put the passed in record into the next available slot -- maybe have an index variable named next_in to indicate where?
•	Move next_in forward.  Remember to wrap back to the beginning if you reach the end of your array
•	If next_in is now equal to your next_out index, move next_out forward one record, again being sure to wrap to the beginning of your array if needed
o	Note that this does mean that you are "throwing away" the record next_out was originally pointing to, but that is okay. That is what a ring buffer is designed to do.
Be sure to make sure that put_fork_record works for both empty buffers and full buffers.  You can include this method at the top of fork.c

Pseudo code for get_fork_record:

•	If next_in == next_out, the buffer is empty. Return an error (-1 is fine).
•	copy item at *next_out into p
•	increment next_out (don't forget to wrap if necessary)
Again, make sure you would work with both empty and full buffers. Since get_fork_record will be used by your /proc module, be sure to export the symbol the way you did in the last lab.

If you get this all implemented, you can compile your new kernel and move it over the HackBox for testing.

Part II: Writing the /proc module
For this part, write a fork_records proc fs entry -- as you did for call_counters to retrieve and display the information you are collecting about fork.
You'll need to declare: struct fork_info record; near the top of your file (in global space).
In fork_record_start(), you'll want to do:
{
    if (get_fork_record(&record) == -1) return NULL;
    return &record;
}
this implies that get_fork_record returns -1 if the buffer is empty.
You can use:
"flags = 0x%08lX, user = %5d, ppid = %5d, cpid = %5d, comm = %8s, return = %ld\n",
in your call to kprintf to display all the various fields.
Once you have completed this work, please submit both your fork_records.c proc code, fork_info.h, plus your modified fork.c code.
Part III: Formatting the /proc data (Graduate students only)
You are allowed to output raw numbers in a user-unfriendly format to the /proc file. However, it is more user friendly if you provided some reasonable formatting of your results.  Write an application that will read the /proc module you've created, and clean up the output.  Your program should do (at least) the following 
•	Format the data in a clean, block structured way (with some reasonable text around it)
•	Convert UID values into actual user names (use the C library function getpwuid). 
•	Convert the clone flags into symbolic constants rather than displaying as a hex value.  You can find the definitions of the clone flags in the /usr/include/clone.h file.
•	If you want to go really above and beyond, convert return values into proper symbolic names. You can consult the clone manual page for a list of possible error returns and cross reference that list with the numbers in the appropriate errno.h files.  You can find these errno files here:
o	include/asm-generic/errno-base.h
o	include/asm-generic/errno.h
To get you started, you can look at this code which shows how to read (and write) from/to the procfs file system. Note that you will only need to read; however, you'll need to read more than the one record that this code reads.